package references

import (
	"jvm/nzpJvm/instructions/base"
	"jvm/nzpJvm/runtime_area"
	"jvm/nzpJvm/runtime_area/heap"
)

// 根据Class类型新建对象实例的指令
type NEW struct{ base.Index16Instruction }

func (self *NEW) Execute(frame *runtime_area.Frame) {
	constantPool := frame.Method().Class().ConstantPool()
	classRef := constantPool.GetConstant(self.Index).(*heap.ClassRef)
	// 将类的符号引用转换为直接引用
	class := classRef.ResolveClass() 

	if !class.InitStart(){
		// 中断当前指令，转而去执行clinit方法，所以当前栈帧要回退到上一条指令。clinit方法返回时，要重新执行这条指令
		// 其实这个clinit方法，可以在类加载的时候就执行，包括在jvm规范中描述的都是在类加载的时候执行
		// 不过Hotspot虚拟机是在实际用到的时候才执行clinit方法
		frame.RevertNextPc()
		base.InitClass(frame.Thread(),class)
		return
	}
	if class.IsInterface() || class.IsAbstract() {
		panic("java.lang.InstantiationError")
	}

	// 新建一个对象
	ref := class.NewObject()
	// 把这个新对象的引用入栈
	frame.OperandStack().PushRef(ref)
}

